
#include <QtGui/qpainter.h>
#include "OpenGLQtWidget.h"
#include "cm_logprint.h"
#include <sys/time.h>
#include "funcs/cm_utils.h"

#define ATTRIB_VERTEX 3
#define ATTRIB_TEXTURE 4

#define VERTEXIN 0
#define TEXTUREIN 1

OpenGLQtWidget::OpenGLQtWidget(QWidget* parent)
	: QOpenGLWidget(parent)
{
    setParent(parent);
#if 0
	QGLWidget *glWidget = new QGLWidget(QGLFormat(QGL::SampleBuffers), this);
	glWidget->makeCurrent();

	QGraphicsView *gview = new QGraphicsView();
	QGraphicsScene *gscene = new QGraphicsScene();

	gview->setScene(gscene);
	gview->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
	gview->setViewport(glWidget);
#endif
    yuvPtr = NULL;
	textureUniformY = 0;
	textureUniformU = 0;
	textureUniformV = 0;
	id_y = 0;
	id_u = 0;
	id_v = 0;
	m_pVSHader = NULL;
	m_pFSHader = NULL;
	m_pShaderProgram = NULL;
	m_pTextureY = NULL;
	m_pTextureU = NULL;
	m_pTextureV = NULL;

	m_first_open = true;

    program = new QOpenGLShaderProgram(this);
}

OpenGLQtWidget::~OpenGLQtWidget()
{
    makeCurrent();
    vbo.destroy();
    textureY->destroy();
    textureU->destroy();
    textureV->destroy();
    doneCurrent();
	if (yuvPtr) {
		delete yuvPtr;
	}
	if (m_pVSHader) {
		delete m_pVSHader;
	}
	if (m_pFSHader) {
		delete m_pFSHader;
	}
	if (m_pShaderProgram) {
		delete m_pShaderProgram;
	}
	//    if (m_pTextureU) {
	//        delete m_pTextureU;
	//    }
	//    if (m_pTextureV) {
	//        delete m_pTextureV;
	//    }
	//    if (m_pTextureY) {
	//        delete m_pTextureY;
	//    }
    yuvPtr = NULL;
	m_pVSHader = NULL;
	m_pFSHader = NULL;
	m_pShaderProgram = NULL;
	m_pTextureY = NULL;
	m_pTextureU = NULL;
	m_pTextureV = NULL;
}

void OpenGLQtWidget::initializeGL2() {
    program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                    "uniform sampler2D y_texture;\n"
                                    "uniform sampler2D uv_texture;\n"
                                    "void main(void)\n"
                                    "{\n"
                                    "   float y, u, v, red, green, blue;\n"
                                    "   y = texture2D(y_texture, gl_TexCoord[0].st).r ;\n"
                                    "   y =  1.1643 * (y - 0.0625);\n"
                                    "   u = texture2D(uv_texture, gl_TexCoord[0].st).r - 0.5;\n"
                                    "   v = texture2D(uv_texture, gl_TexCoord[0].st).a - 0.5;\n"
                                    "   red = y+1.5958*v;\n"
                                    "   green = y-0.39173*u-0.81290*v;\n"
                                    "   blue = y+2.017*u;\n"
                                    "   gl_FragColor = vec4(red, green, blue, 1.0);\n"
                                    "}");

    program->link();
    program->bind();
    glGenTextures(1, &y_texture);
    glGenTextures(1, &uv_texture);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, y_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, videoW, videoH, 0, GL_LUMINANCE,
            GL_UNSIGNED_BYTE, y_data);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, uv_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, videoW>>1, videoH>>1, 0,
            GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, uv_data);

    program->setUniformValue("y_texture", 0);
    program->setUniformValue("uv_texture", 1);

}

void OpenGLQtWidget::paintGL2() {
    glActiveTexture(GL_TEXTURE0);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoW, videoH, GL_LUMINANCE, GL_UNSIGNED_BYTE,
            y_data);
    glActiveTexture(GL_TEXTURE1);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoW>>1, videoH>>1, GL_LUMINANCE_ALPHA,
            GL_UNSIGNED_BYTE, uv_data);


    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);
//    glBegin(GL_QUADS);
//    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.0f);              // Top Left
//    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f);              // Top Right
//    glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 0.0f);              // Bottom Right
//    glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f,-1.0f, 0.0f);              // Bottom Left
//    glEnd();
    glFlush();
    glDisable(GL_TEXTURE_2D);
}

void OpenGLQtWidget::initializeGL3() {
    qDebug() << "initializeGL";

    //初始化opengl （QOpenGLFunctions继承）函数
    initializeOpenGLFunctions();

    //顶点shader
    const char *vString =
            "attribute vec4 vertexPosition;\
        attribute vec2 textureCoordinate;\
        varying vec2 texture_Out;\
        void main(void)\
        {\
            gl_Position = vertexPosition;\
            texture_Out = textureCoordinate;\
        }";
    //片元shader
    const char *tString =
            "precision mediump float;" \
            "varying vec2 texture_Out;\
        uniform sampler2D tex_y;\
        uniform sampler2D tex_u;\
        uniform sampler2D tex_v;\
        void main(void)\
        {\
            vec3 YUV;\
            vec3 RGB;\
            YUV.x = texture2D(tex_y, texture_Out).r;\
            YUV.y = texture2D(tex_u, texture_Out).r - 0.5;\
            YUV.z = texture2D(tex_v, texture_Out).r - 0.5;\
            RGB = mat3(1.0, 1.0, 1.0,\
                0.0, -0.39465, 2.03211,\
                1.13983, -0.58060, 0.0) * YUV;\
            gl_FragColor = vec4(RGB, 1.0);\
        }";

    //m_program加载shader（顶点和片元）脚本
    //片元（像素）
    qDebug()<<m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, tString);
    //顶点shader
    qDebug() << m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vString);

    //设置顶点位置
    m_program.bindAttributeLocation("vertexPosition",ATTRIB_VERTEX);
    //设置纹理位置
    m_program.bindAttributeLocation("textureCoordinate",ATTRIB_TEXTURE);

    //编译shader
    qDebug() << "m_program.link() = " << m_program.link();

    qDebug() << "m_program.bind() = " << m_program.bind();

    //传递顶点和纹理坐标
    //顶点
    static const GLfloat ver[] = {
            -1.0f,-1.0f,
            1.0f,-1.0f,
            -1.0f, 1.0f,
            1.0f,1.0f
//        -1.0f,-1.0f,
//        0.9f,-1.0f,
//        -1.0f, 1.0f,
//        0.9f,1.0f
    };
    //纹理
    static const GLfloat tex[] = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f
    };

    //设置顶点,纹理数组并启用
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, ver);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, tex);
    glEnableVertexAttribArray(ATTRIB_TEXTURE);

    //从shader获取地址
    m_textureUniformY = m_program.uniformLocation("tex_y");
    m_textureUniformU = m_program.uniformLocation("tex_u");
    m_textureUniformV = m_program.uniformLocation("tex_v");

    //创建纹理
    glGenTextures(1, &m_idy);
    //Y
    glBindTexture(GL_TEXTURE_2D, m_idy);
    //放大过滤，线性插值   GL_NEAREST(效率高，但马赛克严重)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    //U
    glGenTextures(1, &m_idu);
    glBindTexture(GL_TEXTURE_2D, m_idu);
    //放大过滤，线性插值
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    //V
    glGenTextures(1, &m_idv);
    glBindTexture(GL_TEXTURE_2D, m_idv);
    //放大过滤，线性插值
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}

void OpenGLQtWidget::paintGL3() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_idy);
    //修改纹理内容(复制内存内容)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_BITS, videoW, videoH, 0, GL_RED_BITS, GL_UNSIGNED_BYTE,yuvPtr);
    //与shader 关联
    glUniform1i(m_textureUniformY, 0);

    glActiveTexture(GL_TEXTURE0+1);
    glBindTexture(GL_TEXTURE_2D, m_idu);
    //修改纹理内容(复制内存内容)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_BITS, videoW/2, videoH/2, 0, GL_RED_BITS, GL_UNSIGNED_BYTE,
            yuvPtr+videoW*videoH);
    //与shader 关联
    glUniform1i(m_textureUniformU,1);

    glActiveTexture(GL_TEXTURE0+2);
    glBindTexture(GL_TEXTURE_2D, m_idv);
    //修改纹理内容(复制内存内容)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_BITS, videoW/2, videoH/2, 0, GL_RED_BITS, GL_UNSIGNED_BYTE,
            yuvPtr+videoW*videoH*5/4);
    //与shader 关联
    glUniform1i(m_textureUniformV, 2);

    glDrawArrays(GL_TRIANGLE_STRIP,0,4);
}

void OpenGLQtWidget::initializeGL4() {
    initializeOpenGLFunctions();
    const char *vsrc =
            "attribute vec4 vertexIn; \
             attribute vec4 textureIn; \
             varying vec4 textureOut;  \
             uniform mediump mat4 matrix;\
             void main(void)           \
             {                         \
                 gl_Position = vertexIn * matrix; \
                 textureOut = textureIn; \
             }";

    const char *fsrc =
            "precision mediump float; \n"
            "varying mediump vec4 textureOut;\n"
            "uniform sampler2D textureY;\n"
            "uniform sampler2D textureUV;\n"
            "void main(void)\n"
            "{\n"
            "vec3 yuv; \n"
            "vec3 rgb; \n"
            "yuv.x = texture2D(textureY, textureOut.st).r - 0.0625; \n"
            "yuv.y = texture2D(textureUV, textureOut.st).r - 0.5; \n"
            "yuv.z = texture2D(textureUV, textureOut.st).g - 0.5; \n"
            "rgb = mat3( 1,       1,         1, \n"
            "0,       -0.39465,  2.03211, \n"
            "1.13983, -0.58060,  0) * yuv; \n"
            "gl_FragColor = vec4(rgb, 1); \n"
            "}\n";

    qDebug() << program->addShaderFromSourceCode(QOpenGLShader::Vertex,vsrc);
    qDebug() << program->addShaderFromSourceCode(QOpenGLShader::Fragment,fsrc);
    qDebug() << program->link();
    qDebug() << program->bind();

    GLfloat points[]{
            -0.8f, 0.8f,
            0.8f, 0.8f,
            0.8f, -0.8f,
            -0.8f, -0.8f,

            0.0f,1.0f,
            1.0f,1.0f,
            1.0f,0.0f,
            0.0f,0.0f,
    };

    vbo.create();
    vbo.bind();
    vbo.allocate(points,sizeof(points));
    //不能在这里直接将program绑定，以及vbo等等,感觉这里的program整个渲染的一部分,还有其它的program，必须在render()函数中进行数据的绑定和纹理的生成
    GLuint ids[2];
    glGenTextures(2,ids);
    idY = ids[0];
    idUV = ids[1];
    m_fAngle = 0.0;
    m_fScale = 1.0;
}

void OpenGLQtWidget::paintGL4() {
    glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);

    program->bind(); //使用opengl切换为当前的program以使用shader
    QMatrix4x4 modelview;
    modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
    modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
    modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
    modelview.scale(m_fScale);
    modelview.translate(0.0f, -0.2f, 0.0f);
    program->setUniformValue("matrix", modelview);

    vbo.bind(); //切换并使用创建好的顶点和纹理坐标数据
    program->enableAttributeArray("vertexIn");
    program->enableAttributeArray("textureIn");
    program->setAttributeBuffer("vertexIn",GL_FLOAT, 0, 2, 2*sizeof(GLfloat));
    program->setAttributeBuffer("textureIn",GL_FLOAT,2 * 4 * sizeof(GLfloat),2,2*sizeof(GLfloat));

    glActiveTexture(GL_TEXTURE0 + 1);
    //这里我试了有个奇葩的现象，必须先选择1号纹理用来渲染Y分量数据，然后必须使用0号纹理来渲染UV分量的数据，原因我暂时也还没搞清楚
    glBindTexture(GL_TEXTURE_2D,idY); //这真是一个大坑，我整了很久
    glTexImage2D(GL_TEXTURE_2D,0,GL_RED_BITS,videoW,videoH,0,GL_RED_BITS,GL_UNSIGNED_BYTE,yuvPtr);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glActiveTexture(GL_TEXTURE0 + 0); //使用0号纹理填充UV分量的数据
    glBindTexture(GL_TEXTURE_2D,idUV);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RED_BITS,videoW >> 1,videoH >> 1,0,GL_RED_BITS,GL_UNSIGNED_BYTE,
            yuvPtr +
    videoW*videoH);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    program->setUniformValue("textureUV",0);
    program->setUniformValue("textureY",1);
#ifdef NORMAL_PC
    glDrawArrays(GL_QUADS,0,4);
#else
    glDrawArrays(GL_QUADS_EXT,0,4);
#endif
    program->disableAttributeArray("vertexIn");
    program->disableAttributeArray("textureIn");
    program->release(); //去掉program的绑定

    m_fAngle += 1.0f;
}

void OpenGLQtWidget::initializeGLEasy() {

    GLfloat vertex[] = {
            -0.5f, 0.0f,
            0.5f, 0.0f,
            0.0f, 0.5f,
    };

//三角形顶点索引
    GLuint triIndexs[] = {0, 1, 2};

//三角形顶点颜色
    GLfloat colors[] = {1.0f, 0.0f, 0.0f, 1.0f,
                        0.0f, 1.0f, 0.0f, 1.0f,
                        0.0f, 0.0f, 1.0f, 1.0f,
    };

    const char* VERTEX_SHADER_CODE = "uniform mat4 matrix; \
    attribute vec4 vPosition;\
    attribute vec4 vColor;\
    varying vec4 fColor; \
    void main(void) \
    { \
        fColor = vColor;\
        gl_Position = matrix * vPosition;\
    }";

    const char* FRAGMENT_SHADER_CODE =
            "precision mediump float;\
            varying vec4 fColor; \
    void main(void) \
    { \
        gl_FragColor = fColor; \
    }";

    initializeOpenGLFunctions();

    OpenGLFeatures features = openGLFeatures();
    printf("support framebuffers [%x]\n", features);
    if (features & Framebuffers)
    {
        printf("support framebuffers [%x]\n", features);
    }
    qDebug() << program->addShaderFromSourceCode(QOpenGLShader::Vertex, VERTEX_SHADER_CODE) ;
    qDebug() << program->addShaderFromSourceCode(QOpenGLShader::Fragment, FRAGMENT_SHADER_CODE);

    qDebug() << program->link();
    qDebug() << program->bind();

    // 获取shaderprogram的id号，然后可以通过id号获取一些属性...
    GLuint programId = program->programId();

    // 从shaderprogram里面获取变量标识
    matrixLocation = glGetUniformLocation(programId, "matrix");
    vertexLocation = glGetAttribLocation(programId, "vPosition");
    clorLocation = glGetAttribLocation(programId, "vColor");

    size_t vVerticesLen = sizeof(vertex)/sizeof(GLfloat);
    size_t triIndexLen = sizeof(triIndexs)/sizeof(GLuint);
    size_t colorsLen = sizeof(colors)/sizeof(GLfloat);

    // 初始化顶点buffer并装载数据到显存
    glGenBuffers(1, &verVbo);
    glBindBuffer(GL_ARRAY_BUFFER, verVbo);
    glBufferData(GL_ARRAY_BUFFER, vVerticesLen * sizeof(GLfloat), vertex, GL_STATIC_DRAW);

    // 初始化索引buffer并装载数据到显存
    glGenBuffers(1, &indexVbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, triIndexLen * sizeof(GLuint), triIndexs, GL_STATIC_DRAW);

    // 初始化颜色buffer并装载数据到显存
    glGenBuffers(1, &colorVbo);
    glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
    glBufferData(GL_ARRAY_BUFFER, colorsLen * sizeof(GLfloat), colors, GL_STATIC_DRAW);
}

void OpenGLQtWidget::paintGLEasy() {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    // shader传入模型视图矩阵 projection可以理解为建立了一个坐标系空间，可以再这个空间内设置图形
    glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, projection.data());

    // shader绑定并启用颜色数组buffer
    glBindBuffer(GL_ARRAY_BUFFER,colorVbo);
    glVertexAttribPointer(clorLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(clorLocation);
    // 颜色值rgba，所以每四个float值作为一个颜色值，如果只是希望rgb，取三个值作为颜色值即可!


    // shader绑定并启用顶点数组buffer
    glBindBuffer(GL_ARRAY_BUFFER, verVbo);
    glVertexAttribPointer( vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(vertexLocation);

    // shader绑定并顶点索引数组buffer - 索引无需启用
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indexVbo);
    glDrawElements(GL_TRIANGLES, triIndexLen, GL_UNSIGNED_INT,0);

    // 解绑buffer、关闭启用顶点、颜色数组
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableVertexAttribArray(vertexLocation);
    glDisableVertexAttribArray(clorLocation);
}

void OpenGLQtWidget::initializeGL()
{
    cmdebug("init\n");
//    initializeGL4();
    initializeGLEasy();
    return;
	initializeOpenGLFunctions();

    glEnable(GL_DEPTH_TEST);

    static const GLfloat vertices[]{
            //顶点坐标
            -1.0f,-1.0f,
            -1.0f,+1.0f,
            +1.0f,+1.0f,
            +1.0f,-1.0f,
            //纹理坐标
            0.0f,1.0f,
            0.0f,0.0f,
            1.0f,0.0f,
            1.0f,1.0f,
    };

    vbo.create();
    vbo.bind();
    vbo.allocate(vertices,sizeof(vertices));

    QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex,this);
    const char *vsrc =
            "attribute highp vec4 vertexIn; \
    attribute highp vec2 textureIn; \
    varying vec2 textureOut;  \
    void main(void)           \
    {                         \
        gl_Position = vertexIn; \
        textureOut = textureIn; \
    }";
    vshader->compileSourceCode(vsrc);

    QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment,this);
    const char *fsrc =
    "precision mediump float; \
    varying vec2 textureOut; \
    uniform mediump sampler2D tex_y; \
    uniform mediump sampler2D tex_u; \
    uniform mediump sampler2D tex_v; \
    void main(void) \
    { \
        vec3 yuv; \
        vec3 rgb; \
        yuv.x = texture2D(tex_y, textureOut).r; \
        yuv.y = texture2D(tex_u, textureOut).r - 0.5; \
        yuv.z = texture2D(tex_v, textureOut).r - 0.5; \
        rgb = mat3( 1,       1,         1, \
                    0,       -0.39465,  2.03211, \
                    1.13983, -0.58060,  0) * yuv; \
        gl_FragColor = vec4(rgb, 1); \
    }";
    fshader->compileSourceCode(fsrc);

    program->addShader(vshader);
    program->addShader(fshader);
    program->bindAttributeLocation("vertexIn",VERTEXIN);
    program->bindAttributeLocation("textureIn",TEXTUREIN);
    program->link();
    program->bind();
    program->enableAttributeArray(VERTEXIN);
    program->enableAttributeArray(TEXTUREIN);
    program->setAttributeBuffer(VERTEXIN,GL_FLOAT,0,2,2*sizeof(GLfloat));
    program->setAttributeBuffer(TEXTUREIN,GL_FLOAT,8*sizeof(GLfloat),2,2*sizeof(GLfloat));

    textureUniformY = program->uniformLocation("tex_y");
    textureUniformU = program->uniformLocation("tex_u");
    textureUniformV = program->uniformLocation("tex_v");
    textureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
    textureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
    textureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
    textureY->create();
    textureU->create();
    textureV->create();
    id_y = textureY->textureId();
    id_u = textureU->textureId();
    id_v = textureV->textureId();
    glClearColor(1.0, 0.0, 0.0, 1.0);
}

void OpenGLQtWidget::resizeGL(int w, int h)
{
	if (h == 0)// ��ֹ�����
	{
		h = 1;// ������Ϊ1
	}
	//�����ӿ�
	resize(w, h);
	glViewport(0, 0, w, h);
	printf("set size [%d, %d]\n", w,h );
}

void OpenGLQtWidget::paintGL()
{
//    paintGL4();
    paintGLEasy();
    return;
//    cmdebug("render\n");
    glEnable(GL_DEPTH_TEST);
//    QMatrix4x4 m;
//    m.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f );//透视矩阵随距离的变化，图形跟着变化。屏幕平面中心就是视点（摄像头）,需要将图形移向屏幕里面一定距离。
//    m.ortho(-2,+2,-2,+2,-10,10);//近裁剪平面是一个矩形,矩形左下角点三维空间坐标是（left,bottom,-near）,右上角点是（right,top,-near）所以此处为负，表示z轴最大为10；
    //远裁剪平面也是一个矩形,左下角点空间坐标是（left,bottom,-far）,右上角点是（right,top,-far）所以此处为正，表示z轴最小为-10；
    //此时坐标中心还是在屏幕水平面中间，只是前后左右的距离已限制。
    glActiveTexture(GL_TEXTURE0);  //激活纹理单元GL_TEXTURE0,系统里面的
    glBindTexture(GL_TEXTURE_2D,id_y); //绑定y分量纹理对象id到激活的纹理单元
    //使用内存中的数据创建真正的y分量纹理数据
    glTexImage2D(GL_TEXTURE_2D,0,GL_RED_BITS,videoW,videoH,0,GL_RED_BITS,GL_UNSIGNED_BYTE,yuvPtr);
    //https://blog.csdn.net/xipiaoyouzi/article/details/53584798 纹理参数解析
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glActiveTexture(GL_TEXTURE1); //激活纹理单元GL_TEXTURE1
    glBindTexture(GL_TEXTURE1,id_u);
    //使用内存中的数据创建真正的u分量纹理数据
    glTexImage2D(GL_TEXTURE_2D,0,GL_RED_BITS,videoW >> 1, videoH >> 1,0,GL_RED_BITS,GL_UNSIGNED_BYTE,yuvPtr + videoW * videoH);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glActiveTexture(GL_TEXTURE2); //激活纹理单元GL_TEXTURE2
    glBindTexture(GL_TEXTURE_2D,id_v);
    //使用内存中的数据创建真正的v分量纹理数据
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_BITS, videoW >> 1, videoH >> 1, 0, GL_RED_BITS, GL_UNSIGNED_BYTE, yuvPtr+videoW*videoH*5/4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    //指定y纹理要使用新值
    glUniform1i(textureUniformY, 0);
    //指定u纹理要使用新值
    glUniform1i(textureUniformU, 1);
    //指定v纹理要使用新值
    glUniform1i(textureUniformV, 2);
    //使用顶点数组方式绘制图形
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    glDisable(GL_DEPTH_TEST);
}

void OpenGLQtWidget::set_data(unsigned char *buf, int width, int height)
{
#if 0
	play(buf, width, height);
#else
	int len = width*height * 3 / 2;
	if (!yuvPtr)
	{
        yuvPtr = new unsigned char[len];
	}
	unsigned long long s = cm_gettime_milli();
	memcpy(yuvPtr, buf, len);
	unsigned long long e = cm_gettime_milli();
	printf("----------use time [%llu]\n", e-s);
    videoW = width;
    videoH = height;

    update();
#endif
}
